package room

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gookit/validate"
	"github.com/nfnt/resize"
	"github.com/skip2/go-qrcode"
	"os"
	"strconv"
	"strings"
	"xkginweb/commons/response"
	"xkginweb/global"
	"xkginweb/model/entity/basis"
	basisrequest "xkginweb/model/entity/basis/request"
	resp "xkginweb/model/entity/comms/response"
	"xkginweb/model/entity/coolingPool"
	poolrequest "xkginweb/model/entity/coolingPool/request"
	"xkginweb/model/entity/importantDevice"
	devicerequest "xkginweb/model/entity/importantDevice/request"
	"xkginweb/model/entity/importantPort"
	portquest "xkginweb/model/entity/importantPort/request"
	"xkginweb/model/entity/room"
	"xkginweb/model/entity/room/request"
	qrcodeutil "xkginweb/utils/qrcode"
)

// 定义api接口
type RoomApi struct {
	global.BaseApi
}

func (api *RoomApi) CreateRoom(c *gin.Context) {
	// 1: 第一件事情就准备数据的载体
	var room room.QccRoom
	err := c.ShouldBindJSON(&room)
	if err != nil {
		// 如果参数注入失败或者出错就返回接口调用这。出错了.
		response.FailWithMessage(err.Error(), c)
		return
	}

	// 创建实例，保存房间
	err = RoomService.CreateRoom(&room)
	// 如果保存失败。就返回创建失败的提升
	if err != nil {
		response.FailWithMessage("创建失败", c)
		return
	}
	// 如果保存成功，就返回创建创建成功
	response.Ok("创建成功", c)
}

func (api *RoomApi) UpdateRoom(c *gin.Context) {
	// 1: 第一件事情就准备数据的载体
	var room room.QccRoom
	err := c.ShouldBindJSON(&room)
	if err != nil {
		// 如果参数注入失败或者出错就返回接口调用这。出错了.
		response.FailWithMessage(err.Error(), c)
		return
	}

	err = RoomService.UpdateRoom(&room)
	// 如果保存失败。就返回创建失败的提升
	if err != nil {
		response.FailWithMessage("更新失败", c)
		return
	}
	// 如果保存成功，就返回创建创建成功
	response.Ok("更新成功", c)
}

// 根据ID查询房间明细

func (api *RoomApi) GetRoom(c *gin.Context) {
	// 绑定参数用来获取/:id这个方式
	id := c.Param("id")
	// 开始执行
	parseUint, _ := strconv.ParseUint(id, 10, 64)

	data, err := RoomService.GetRoom(uint(parseUint))
	if err != nil {
		response.FailWithMessage("获取失败", c)
		return
	}

	response.Ok(data, c)
}

// http://localhost:8888/room/delete/:id

func (api *RoomApi) DeleteById(c *gin.Context) {
	// 绑定参数用来获取/:id这个方式
	id := c.Param("id")
	// 开始执行
	parseUint, _ := strconv.ParseUint(id, 10, 64)
	err := RoomService.DeleteRoomById(uint(parseUint))
	if err != nil {
		response.FailWithMessage("删除失败", c)
		return
	}
	response.Ok("ok", c)
}

func (api *RoomApi) GetRoomDetail(c *gin.Context) {
	// 绑定参数用来获取/:id这个方式
	id := c.Param("id")
	// 这个是用来获取?age=123
	//age := c.Query("age")
	parseUint, _ := strconv.ParseUint(id, 10, 64)
	data, err := RoomService.GetRoom(uint(parseUint))
	if err != nil {
		response.FailWithMessage("获取失败", c)
		return
	}
	response.Ok(data, c)
}

func (api *RoomApi) LoadRoomPage(c *gin.Context) {
	// 创建一个分页对象
	var pageInfo request.RoomPageInfo
	// 把前端json的参数传入给PageInfo
	err := c.ShouldBindJSON(&pageInfo)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	roomPage, total, err := RoomService.LoadRoomPage(pageInfo)
	if err != nil {
		response.FailWithMessage("获取失败"+err.Error(), c)
		return
	}
	response.Ok(resp.PageResult{
		List:     roomPage,
		Total:    total,
		Page:     pageInfo.Page,
		PageSize: pageInfo.PageSize,
	}, c)
}
func (api *RoomApi) LoadRoom(c *gin.Context) {
	// 创建一个分页对象
	var pageInfo request.RoomPageInfoList
	// 把前端json的参数传入给PageInfo
	err := c.ShouldBindJSON(&pageInfo)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	room, err := RoomService.LoadRoom(pageInfo)
	if err != nil {
		response.FailWithMessage("获取失败"+err.Error(), c)
		return
	}
	response.Ok(room, c)
}

/**查询房间已绑定的冷池*/

func (api *RoomApi) SelectRoomPool(c *gin.Context) {
	// 绑定参数用来获取/:id这个方式
	id := c.Param("id")

	roomId := api.StringToUnit(id)
	if roomId == 0 {
		response.FailWithMessage("请选择一个房间操作", c)
		return
	}
	pools, err := CoolingPoolService.SelectRoomPool(roomId)
	if err != nil {
		response.FailWithMessage("查询失败", c)
		return
	}
	response.Ok(pools, c)
}

// 房间绑定冷池

func (api *RoomApi) BindPool(c *gin.Context) {
	// 1: 第一件事情就准备数据的载体
	var context request.BindPoolContext
	err := c.ShouldBindJSON(&context)
	if err != nil {
		// 如果参数注入失败或者出错就返回接口调用这。出错了.
		response.FailWithBindParams(c)
		return
	}

	//2: 开始验证
	validation := validate.Struct(context)
	if !validation.Validate() {
		response.FailWithValidatorData(validation, c)
		return
	}
	//
	//getRoom, err := RoomService.GetRoom(context.RoomId)
	//if err != nil {
	//	response.FailWithMessage("房间不存在", c)
	//	return
	//}

	// 查询房间原来的绑定数据
	var request poolrequest.CoolingPoolInfo
	request.RoomId = &context.RoomId
	list, err := CoolingPoolService.LoadCoolingPool(request)
	if err != nil {
		response.FailWithMessage("已绑定冷池查询失败", c)
		return
	}
	// 使用map来记录结构体中存在的ID
	idExists := make(map[uint]bool)
	for _, item := range list {
		idExists[item.CoolingPoolId] = true
	}
	// 清除原先的冷池的绑定数据
	for _, item := range list {
		item.RoomId = 0
		//item.RoomName = ""
		//item.RoomType = 0
	}
	// 把你前端传递过来的冷池ids，进行分割
	poolIdsSplit := strings.Split(context.PoolIds, ",")

	// 遍历结构体切片，更新匹配的ID的房间数据
	for i, item := range list {
		if containsID(poolIdsSplit, item.CoolingPoolId) {
			list[i].RoomId = context.RoomId
			//list[i].RoomName = getRoom.RoomName
			//list[i].RoomType = getRoom.RoomType
		}
	}

	// 扩容结构体，将未匹配的ID对应的冷池数据加入list
	for _, idstr := range poolIdsSplit {
		id := api.StringToUnit(idstr)
		if !idExists[id] {
			qccCoolingPool := coolingPool.QccCoolingPoolList{}
			qccCoolingPool.CoolingPoolId = id
			qccCoolingPool.RoomId = context.RoomId
			//qccCoolingPool.RoomName = getRoom.RoomName
			//qccCoolingPool.RoomType = getRoom.RoomType
			list = append(list, &qccCoolingPool)
		}
	}

	// 创建实例，保存帖子
	err = CoolingPoolService.UpdateRoomPools(list)
	// 如果保存失败。就返回创建失败的提升
	if err != nil {
		response.FailWithMessage("创建失败", c)
		return
	}
	// 如果保存成功，就返回创建创建成功
	response.Ok(list, c)
}

// containsID 检查切片中是否包含特定的ID
func containsID(idsStr []string, targetID uint) bool {
	for _, idStr := range idsStr {
		id, _ := strconv.ParseUint(idStr, 10, 64)
		if uint(id) == targetID {
			return true
		}
	}
	return false
}

/**查询房间已绑定的基础检查项*/

func (api *RoomApi) SelectRoomBasis(c *gin.Context) {
	// 绑定参数用来获取/:id这个方式
	id := c.Param("id")

	roomId := api.StringToUnit(id)
	if roomId == 0 {
		response.FailWithMessage("请选择一个房间操作", c)
		return
	}
	basis, err := BasisService.SelectRoomBasis(roomId)
	if err != nil {
		response.FailWithMessage("查询失败", c)
		return
	}
	response.Ok(basis, c)
}

// 房间绑定冷池

func (api *RoomApi) BindBasis(c *gin.Context) {
	// 1: 第一件事情就准备数据的载体
	var context request.BindBasisContext
	err := c.ShouldBindJSON(&context)
	if err != nil {
		// 如果参数注入失败或者出错就返回接口调用这。出错了.
		response.FailWithBindParams(c)
		return
	}

	//2: 开始验证
	validation := validate.Struct(context)
	if !validation.Validate() {
		response.FailWithValidatorData(validation, c)
		return
	}

	// 查询房间原来的绑定数据
	var request basisrequest.BasisInfo
	request.RoomId = &context.RoomId
	list, err := BasisService.LoadBasis(request)
	if err != nil {
		response.FailWithMessage("已绑定基础项查询失败", c)
		return
	}
	// 使用map来记录结构体中存在的ID
	idExists := make(map[uint]bool)
	for _, item := range list {
		idExists[item.BasisId] = true
	}
	// 清除原先的冷池的绑定数据
	for _, item := range list {
		item.RoomId = 0
	}
	// 把你前端传递过来的冷池ids，进行分割
	basisIdsSplit := strings.Split(context.BasisIds, ",")

	// 遍历结构体切片，更新匹配的ID的房间数据
	for i, item := range list {
		if containsID(basisIdsSplit, item.BasisId) {
			list[i].RoomId = context.RoomId
		}
	}

	// 扩容结构体，将未匹配的ID对应的冷池数据加入list
	for _, idstr := range basisIdsSplit {
		id := api.StringToUnit(idstr)
		if !idExists[id] {
			qccbasis := basis.QccBasisList{}
			qccbasis.BasisId = id
			qccbasis.RoomId = context.RoomId
			list = append(list, &qccbasis)
		}
	}

	// 创建实例，保存帖子
	err = BasisService.UpdateRoomBasis(list)
	// 如果保存失败。就返回创建失败的提升
	if err != nil {
		response.FailWithMessage("创建失败", c)
		return
	}
	// 如果保存成功，就返回创建创建成功
	response.Ok(list, c)
}

/**查询房间已绑定的重要设备*/

func (api *RoomApi) SelectRoomDevice(c *gin.Context) {
	// 绑定参数用来获取/:id这个方式
	id := c.Param("id")

	roomId := api.StringToUnit(id)
	if roomId == 0 {
		response.FailWithMessage("请选择一个房间操作", c)
		return
	}
	devices, err := ImportantDeviceService.SelectRoomDevice(roomId)
	if err != nil {
		response.FailWithMessage("查询失败", c)
		return
	}
	response.Ok(devices, c)
}

// 房间绑定冷池

func (api *RoomApi) BindDevice(c *gin.Context) {
	// 1: 第一件事情就准备数据的载体
	var context request.BindDeviceContext
	err := c.ShouldBindJSON(&context)
	if err != nil {
		// 如果参数注入失败或者出错就返回接口调用这。出错了.
		response.FailWithBindParams(c)
		return
	}

	//2: 开始验证
	validation := validate.Struct(context)
	if !validation.Validate() {
		response.FailWithValidatorData(validation, c)
		return
	}

	// 查询房间原来的绑定数据
	var request devicerequest.ImportantDeviceInfo
	request.RoomId = &context.RoomId
	list, err := ImportantDeviceService.LoadImportantDevice(request)
	if err != nil {
		response.FailWithMessage("已绑定重要设备查询失败", c)
		return
	}
	// 使用map来记录结构体中存在的ID
	idExists := make(map[uint]bool)
	for _, item := range list {
		idExists[item.ImportantDeviceId] = true
	}
	// 清除原先的冷池的绑定数据
	for _, item := range list {
		item.RoomId = 0
	}
	// 把你前端传递过来的冷池ids，进行分割
	deviceIdsSplit := strings.Split(context.ImportantDeviceIds, ",")

	// 遍历结构体切片，更新匹配的ID的房间数据
	for i, item := range list {
		if containsID(deviceIdsSplit, item.ImportantDeviceId) {
			list[i].RoomId = context.RoomId
		}
	}

	// 扩容结构体，将未匹配的ID对应的冷池数据加入list
	for _, idstr := range deviceIdsSplit {
		id := api.StringToUnit(idstr)
		if !idExists[id] {
			qccImportantDevice := importantDevice.QccImportantDeviceList{}
			qccImportantDevice.ImportantDeviceId = id
			qccImportantDevice.RoomId = context.RoomId
			list = append(list, &qccImportantDevice)
		}
	}

	// 创建实例，保存帖子
	err = ImportantDeviceService.UpdateRoomDevice(list)
	// 如果保存失败。就返回创建失败的提升
	if err != nil {
		response.FailWithMessage("创建失败", c)
		return
	}
	// 如果保存成功，就返回创建创建成功
	response.Ok(list, c)
}

/**查询房间已绑定的基础检查项*/

func (api *RoomApi) SelectRoomPort(c *gin.Context) {
	// 绑定参数用来获取/:id这个方式
	id := c.Param("id")

	roomId := api.StringToUnit(id)
	if roomId == 0 {
		response.FailWithMessage("请选择一个房间操作", c)
		return
	}
	ports, err := ImportantPortService.SelectRoomPort(roomId)
	if err != nil {
		response.FailWithMessage("查询失败", c)
		return
	}
	response.Ok(ports, c)
}

// 房间绑定冷池

func (api *RoomApi) BindPort(c *gin.Context) {
	// 1: 第一件事情就准备数据的载体
	var context request.BindPortContext
	err := c.ShouldBindJSON(&context)
	if err != nil {
		// 如果参数注入失败或者出错就返回接口调用这。出错了.
		response.FailWithBindParams(c)
		return
	}

	//2: 开始验证
	validation := validate.Struct(context)
	if !validation.Validate() {
		response.FailWithValidatorData(validation, c)
		return
	}

	// 查询房间原来的绑定数据
	var request portquest.ImportantPortInfo
	request.RoomId = &context.RoomId
	list, err := ImportantPortService.LoadImportantPort(request)
	if err != nil {
		response.FailWithMessage("已绑定基础项查询失败", c)
		return
	}
	// 使用map来记录结构体中存在的ID
	idExists := make(map[uint]bool)
	for _, item := range list {
		idExists[item.ImportantPortId] = true
	}
	// 清除原先的冷池的绑定数据
	for _, item := range list {
		item.RoomId = 0
	}
	// 把你前端传递过来的冷池ids，进行分割
	portIdsSplit := strings.Split(context.ImportantPortIds, ",")

	// 遍历结构体切片，更新匹配的ID的房间数据
	for i, item := range list {
		if containsID(portIdsSplit, item.ImportantPortId) {
			list[i].RoomId = context.RoomId
		}
	}

	// 扩容结构体，将未匹配的ID对应的冷池数据加入list
	for _, idstr := range portIdsSplit {
		id := api.StringToUnit(idstr)
		if !idExists[id] {
			qccImportantPortList := importantPort.QccImportantPortList{}
			qccImportantPortList.ImportantPortId = id
			qccImportantPortList.RoomId = context.RoomId
			list = append(list, &qccImportantPortList)
		}
	}

	// 创建实例，保存帖子
	err = ImportantPortService.UpdateRoomPort(list)
	// 如果保存失败。就返回创建失败的提升
	if err != nil {
		response.FailWithMessage("创建失败", c)
		return
	}
	// 如果保存成功，就返回创建创建成功
	response.Ok(list, c)
}

/**批量下载房间二维码**/

func (api *RoomApi) PullQrCode(c *gin.Context) {
	// 二维码下载目录
	downloadDir := "qrcodes"
	// 打包后的压缩包文件名
	zipFileName := "qrcodes.zip"

	// 创建二维码下载目录
	err := os.MkdirAll(downloadDir, os.ModePerm)
	if err != nil {
		response.FailWithMessage("创建下载目录时发生错误", c)
		return
	}
	// 在请求处理结束后删除临时目录及其内容
	defer func(path string) {
		err := os.RemoveAll(path)
		if err != nil {
			response.FailWithMessage("删除临时目录时发生错误", c)
		}
	}(downloadDir)
	defer func(path string) { // 在请求处理结束后删除临时zip
		err := os.RemoveAll(path)
		if err != nil {
			response.FailWithMessage("删除临时zip时发生错误", c)
		}
	}(zipFileName)
	var pageInfo = request.RoomPageInfoList{}
	list, err := RoomService.LoadRoom(pageInfo)
	if err != nil {
		response.FailWithMessage("获取房间失败失败", c)
		return
	}

	// 生成二维码并下载
	for i := 1; i <= len(list); i++ {
		content := fmt.Sprintf("http://121.40.145.243:5438/#/pages/index/index?aaa=%d", list[i].RoomId)
		qrCode, err := qrcode.New(content, qrcode.Medium)
		if err != nil {
			response.FailWithMessage("生成二维码时发生错误", c)
			return
		}

		// 调整二维码大小
		qrCodeImage := resize.Resize(200, 200, qrCode.Image(256), resize.Lanczos3)

		// 保存二维码图片
		fileName := fmt.Sprintf("%s/%s.png", downloadDir, list[i].RoomName)
		err = qrcodeutil.SaveQRCodeImage(fileName, qrCodeImage)
		if err != nil {
			response.FailWithMessage("保存二维码图片时发生错误", c)
			return
		}
	}

	// 压缩二维码文件夹
	err = qrcodeutil.ZipFiles(zipFileName, downloadDir)
	if err != nil {
		response.FailWithMessage("创建压缩文件时发生错误", c)
		return
	}

	fmt.Println("二维码下载并打包成功.")

	// 设置响应头，指定文件名以及告诉浏览器要下载文件
	c.Header("Content-Type", "application/octet-stream;charset=UTF-8")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", zipFileName))

	c.File(zipFileName)
}
